﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;

namespace SilverNotes
{
  /// <summary>
  /// Creates an image-based preview of a control.
  /// </summary>
  public class ControlPreview : ContentControl
  {
    private Action _action;

    public FrameworkElement UIContent
    {
      get { return (FrameworkElement)GetValue(UIContentProperty); }
      set { SetValue(UIContentProperty, value); }
    }

    public static readonly DependencyProperty UIContentProperty =
      DependencyProperty.Register("UIContent", typeof(FrameworkElement), typeof(ControlPreview), new PropertyMetadata(null, UIContentPropertyChanged));


    private static void UIContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      var cp = (ControlPreview) d;
      cp.OnUIContentChanged((FrameworkElement)e.NewValue);
    }

    private void OnUIContentChanged(FrameworkElement newValue)
    {
      if (CanGeneratePreview(newValue))
      {
        Content = GeneratePreview(newValue);
      }
      else
      {
        WhenCanGeneratePreview(newValue, () => Content = GeneratePreview(newValue));
        Content = newValue; // Set the content to real value, until we can generate the preview.
      }
    }

    private void WhenCanGeneratePreview(FrameworkElement source, Action action)
    {
      _action = action;
      source.Loaded += SourceLoaded;
    }

    private void SourceLoaded(object sender, RoutedEventArgs e)
    {
      var fe = (FrameworkElement) sender;
      fe.Loaded -= SourceLoaded;
      if (_action != null)
      {
        _action();
      }
    }

    private Image GeneratePreview(FrameworkElement source)
    {
      var preview = new Image();

      // TODO: Monitor if needed.
      var wb = new WriteableBitmap(source, null);
      preview.Source = wb;
      
      if (UIContent == Content)
      {
        // We should detach it from our tree, to let it appear in other parts:
        Content = null;
      }
      return preview;
    }

    private static bool CanGeneratePreview(FrameworkElement fe)
    {
      return (fe.Parent != null);
    }
  }
}